package com.hadluo.qq.client.websocket;

import com.alibaba.fastjson.JSON;
import com.hadluo.qq.client.model.GroupMessage;
import com.hadluo.qq.client.model.Message;
import com.hadluo.qq.client.model.UserInfo;
import com.hadluo.qq.client.event.MessageEvent;
import com.hadluo.qq.client.event.UserStatusEvent;

import com.hadluo.qq.client.utils.Constants;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.util.*;

import static com.hadluo.qq.client.utils.Constants.SERVER_HOST;

public class QQWebSocketClient extends org.java_websocket.client.WebSocketClient {
    private UserInfo currentUser;
    private List<MessageListener> messageListeners = new ArrayList<>();
    private List<UserStatusListener> statusListeners = new ArrayList<>();
    private static QQWebSocketClient instance;


    public QQWebSocketClient(URI serverUri) {
        super(serverUri);
    }

    public static QQWebSocketClient getInstance() {
        if (instance == null) {
            throw new IllegalStateException("WebSocket客户端尚未初始化，请先调用connect方法");
        }
        return instance;
    }

    public static void connect(UserInfo user) {
        try {
            String wsUrl = String.format("ws://"+ SERVER_HOST+":8080/ws/%s", user.getQqNumber());
            URI serverUri = new URI(wsUrl);
            if (instance != null) {
                instance.close();
            }
            QQWebSocketClient newInstance = new QQWebSocketClient(serverUri);
            newInstance.currentUser = user;
            newInstance.connect();
            instance = newInstance;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onOpen(ServerHandshake handshakedata) {
        System.out.println("WebSocket连接已建立");
    }

    @Override
    public void onMessage(String message) {
        System.out.println("[WebSocket] 收到消息: " + message);
        try {
            // 解析消息类型
            Map<String, Object> messageMap = JSON.parseObject(message);
            String type = (String) messageMap.get("type");

            switch (type) {
                case "STATUS":
                    // 解析用户状态消息
                    UserStatusEvent statusEvent = new UserStatusEvent();
                    statusEvent.setUserId(messageMap.get("userId").toString());
                    statusEvent.setOnline((Boolean) messageMap.get("online"));
//                    statusEvent.setCreateTime((Long) messageMap.get("timestamp"));
                    notifyStatusListeners(statusEvent);
                    break;

                case "text":
                case "image":
                    // 解析聊天消息
                    MessageEvent chatEvent = new MessageEvent();
                    Message chatMessage = new Message();
                    chatMessage.setSenderId(Long.parseLong(messageMap.get("fromUserId").toString()));
                    chatMessage.setReceiverId(Long.parseLong(messageMap.get("targetUserId").toString()));
                    chatMessage.setContent(messageMap.get("content").toString());
                    chatMessage.setCreateTime(new Date((Long) messageMap.get("timestamp")));
                    chatEvent.setMessage(chatMessage);
                    notifyMessageListeners(chatEvent);
                    break;
                case "group-text":
                case "group-image":
                    GroupMessage groupMessage = JSON.parseObject(message , GroupMessage.class);
                    // 解析聊天消息
                    MessageEvent event = new MessageEvent();
                    event.setGroupMessage(groupMessage);
                    notifyMessageListeners(event);
                    break;

                case "ERROR":
                    System.out.println("[WebSocket] 收到错误消息: " + messageMap.get("message"));
                    break;

                case "heartbeat":
                    // 心跳消息，不需要特殊处理
                    break;
                case "shake":
                    // 解析抖动消息
                    MessageEvent shakeEvent = new MessageEvent();
                    Message shakeMessage = new Message();
                    shakeMessage.setSenderId(Long.parseLong(messageMap.get("fromUserId").toString()));
                    shakeMessage.setReceiverId(Long.parseLong(messageMap.get("targetUserId").toString()));
                    shakeMessage.setType(Message.TYPE_SHAKE);
                    shakeMessage.setCreateTime(new Date((Long) messageMap.get("timestamp")));
                    shakeEvent.setMessage(shakeMessage);
                    notifyMessageListeners(shakeEvent);
                    break;

                default:
                    System.out.println("[WebSocket] 收到未知类型消息: " + type);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void sendMessage(Message message) {
        if (isOpen()) {
            // 构造符合服务端要求的消息格式
            Map<String, Object> messageMap = new HashMap<>();
            messageMap.put("targetUserId", message.getReceiverId().toString());
            messageMap.put("content", message.getContent());
            messageMap.put("type", message.getType() != null ? message.getType() : "text"); // 添加消息类型，默认为文本

            String jsonMessage = JSON.toJSONString(messageMap);
            System.out.println("[WebSocket] 发送消息: " + jsonMessage);
            send(jsonMessage);
        }
    }

    public void sendGroupMessage(GroupMessage message , UserInfo userInfo) {
        message.setUser(userInfo);
        if (isOpen()) {
            String jsonMessage = JSON.toJSONString(message);
            System.out.println("[WebSocket] 发送群消息: " + jsonMessage);
            send(jsonMessage);
        }
    }

    @Override
    public void onClose(int code, String reason, boolean remote) {
        System.out.println("WebSocket连接已关闭：" + reason);
        // 尝试重新连接
        if (currentUser != null) {
            new Thread(() -> {
                try {
                    Thread.sleep(5000);
                    connect(currentUser);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }

    @Override
    public void onError(Exception ex) {
        System.out.println("WebSocket发生错误：" + ex.getMessage());
    }

    public void close() {
        if (isOpen()) {
            super.close();
        }
    }

    public void addMessageListener(MessageListener listener) {
        messageListeners.add(listener);
    }

    public void removeMessageListener(MessageListener listener) {
        messageListeners.remove(listener);
    }

    public void addStatusListener(UserStatusListener listener) {
        statusListeners.add(listener);
    }

    public void removeStatusListener(UserStatusListener listener) {
        statusListeners.remove(listener);
    }

    private void notifyMessageListeners(MessageEvent event) {
        for (MessageListener listener : messageListeners) {
            listener.onMessageReceived(event);
        }
    }

    private void notifyStatusListeners(UserStatusEvent event) {
        for (UserStatusListener listener : statusListeners) {
            listener.onStatusChanged(event);
        }
    }

    public interface MessageListener {
        void onMessageReceived(MessageEvent event);
    }

    public interface UserStatusListener {
        void onStatusChanged(UserStatusEvent event);
    }
    public boolean isUserOnline(String userId) {
        try {
            URL url = new URL("http://"+Constants.SERVER_HOST+":8080/api/user/status/" + userId);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(5000);

            int responseCode = conn.getResponseCode();
            if (responseCode == 200) {
                BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                String response = in.readLine();
                in.close();

                Map<String, Object> result = JSON.parseObject(response);
                return (Boolean) result.get("online");
            }
            return false;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
}